﻿// Jinx AJAX Framework
// Copyright (C) 2008 Blake Hegerle
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.IO;
using System.Net;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;
using Jinx.Communications.Hosting;

namespace Jinx.Communications.Views
{
    using ContentFactory = Func<string, Stream>;

    public class ViewServer : IServer
    {
        private readonly string ContentType;

        private readonly XslCompiledTransform Transform;

        public ViewServer(Stream TransformStream, string contentType, ContentFactory ContentFactory)
        {
            ContentType = contentType;
            Transform = new XslCompiledTransform();
            Transform.Load(new XmlTextReader(TransformStream), null, new Resolver(ContentFactory));
        }

        #region IServer Members

        public void ProcessRequest(HttpListenerContext Context, string RelativePath)
        {
            using (Context.Response)
            {
                try
                {
                    if (string.IsNullOrEmpty(RelativePath))
                        RelativePath = Constants.Views.MAIN_VIEW_NAME;

                    var Document = GetDocument(RelativePath);

                    Context.Response.ContentType = ContentType;
                    Context.Response.StatusCode = 200;

                    var Args = new XsltArgumentList();
                    Transform.Transform(Document, Args, Context.Response.OutputStream);
                }
                catch (FileNotFoundException)
                {
                    Context.Response.StatusCode = 404;
                }
                catch
                {
                    Context.Response.StatusCode = 500;
                }
            }
        }

        #endregion

        private static XPathDocument GetDocument(string RelativePath)
        {
            using (var FileStream = File.Open(RelativePath, FileMode.Open))
                return new XPathDocument(FileStream);
        }

        #region Nested type: Resolver

        private class Resolver : XmlResolver
        {
            private readonly ContentFactory ContentFactory;

            public Resolver(ContentFactory ContentFactory)
            {
                this.ContentFactory = ContentFactory;
            }

            public override ICredentials Credentials
            {
                set { throw new NotImplementedException(); }
            }

            public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn)
            {
                var Path = absoluteUri.LocalPath.Trim('/');

                return ContentFactory(Path);
            }

            public override Uri ResolveUri(Uri baseUri, string relativeUri)
            {
                var Builder = new UriBuilder {Scheme = "resource", Path = relativeUri};

                return Builder.Uri;
            }
        }

        #endregion
    }
}